import Flutter
import UIKit

public class GTLibCoreFlutterPlugin: NSObject, FlutterPlugin, FlutterStreamHandler {
    
    // 多引擎 MessageChannel 存储
    internal static var messageChannelList: [GTMessageChannelFlutterApi?] = []
    // 多引擎 methodChannel 存储
    fileprivate static var methodChannelSet: Set<FlutterMethodChannel?> = []
    
    // MethodChannel
    var methodChannel: FlutterMethodChannel? = nil
    // EventChannel
    var eventChannel: FlutterEventChannel? = nil
    var eventSink: FlutterEventSink? = nil
    // messageChannel
    var messageChannelFlutterApi: GTMessageChannelFlutterApi? = nil
    
    public static func register(with registrar: FlutterPluginRegistrar) {
        print("GTLibCoreFlutterPlugin - register")
        
        let instance = GTLibCoreFlutterPlugin()
        
        // FlutterMethodChannel
        let methodChannel = FlutterMethodChannel(name: "com.gateio.flutter.lib_core.MethodChannel",
                                           binaryMessenger: registrar.messenger())
        registrar.addMethodCallDelegate(instance, channel: methodChannel)

        instance.methodChannel = methodChannel
        GTLibCoreFlutterPlugin.methodChannelSet.insert(methodChannel)
        
        // FlutterEventChannel
        instance.eventChannel = FlutterEventChannel(name: "com.gateio.flutter.lib_core.EventChannel",
                                                    binaryMessenger: registrar.messenger())
        instance.eventChannel?.setStreamHandler(instance)
        
        // GTMessageChannelHostApi 设置实现类
        GTMessageChannelHostApiSetup.setUp(binaryMessenger: registrar.messenger(),
                                           api: GTFlutterMessageChannelImpl.shared)
        // GTMessageChannelFlutterApi 设置实现类
        instance.messageChannelFlutterApi = GTMessageChannelFlutterApi(binaryMessenger: registrar.messenger())
        messageChannelList.append(instance.messageChannelFlutterApi)
        
        // GTLogger 设置实现类
        GTLoggerHostApiSetup.setUp(binaryMessenger: registrar.messenger(), api: GTLoggerHostApiImpl())
        
        registrar.publish(instance)
    }
    
    public func detachFromEngine(for registrar: FlutterPluginRegistrar) {
        debugPrint("GTLibCoreFlutterPlugin - detachFromEngine")
        
        GTLibCoreFlutterPlugin.methodChannelSet.remove(self.methodChannel)

        GTLibCoreFlutterPlugin.eventSinkSet.remove(self)
        eventChannel?.setStreamHandler(nil)
        eventChannel = nil
        eventSink = nil
        
        GTLibCoreFlutterPlugin.messageChannelList.removeAll { $0 == nil}
        GTLibCoreFlutterPlugin.messageChannelList = GTLibCoreFlutterPlugin.messageChannelList.filter {
            $0 !== self.messageChannelFlutterApi
        }
    }

    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        switch call.method {
        case "notifyMultiEngineSync":
            // 数据直接返回给 各Flutter 引擎
            GTLibCoreFlutterPlugin.methodChannelSet.forEach { methodChannel in
                methodChannel?.invokeMethod("listenMultiEngineSync", arguments: call.arguments)
            }
            break
        default:
            result(FlutterMethodNotImplemented)
        }
    }

    public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
        debugPrint("GTLibCoreFlutterPlugin - onListen")
    
        self.eventSink = events
        GTLibCoreFlutterPlugin.eventSinkSet.insert(self)
        // 发送 粘性消息
        GTLibCoreFlutterPlugin.globalStickyMessageSet.forEach { messageDic in
            self.eventSink?(messageDic)
        }
        GTLibCoreFlutterPlugin.globalStickyMessageSet.removeAll()
        return nil
    }
    
    public func onCancel(withArguments arguments: Any?) -> FlutterError? {
        debugPrint("GTLibCoreFlutterPlugin - onCancel")
        
        GTLibCoreFlutterPlugin.eventSinkSet.remove(self)
        self.eventSink = nil
        return nil
    }
    
}


extension GTLibCoreFlutterPlugin {
    
    // 多引擎 EventChannel 存储
    fileprivate static var eventSinkSet: Set<GTLibCoreFlutterPlugin> = []
    // 保存粘性消息
    fileprivate static var globalStickyMessageSet: Set<String> = []

    public static func sendMessage(_ eventModel: GTFlutterEventModel, sticky: Bool = false) {
        if (eventModel.actionName.isEmpty) {
            debugPrint("GTLibCoreFlutterPlugin - The action is invali.")
            return
        }
        
        guard let eventModelJsonData = try? JSONEncoder().encode(eventModel) else {
            debugPrint("GTLibCoreFlutterPlugin - The message is invali.")
            return
        }
        let messageDic: [String: String?] = [
            "actionType": eventModel.actionType,
            "actionName": eventModel.actionName,
            "dataJson": String(decoding: eventModelJsonData, as: UTF8.self)
        ]
        
        guard let messageJsonData = try? JSONEncoder().encode(messageDic) else {
            debugPrint("GTLibCoreFlutterPlugin - The message is invali.")
            return
        }
        let messageJson = String(decoding: messageJsonData, as: UTF8.self)
        
        if (eventSinkSet.isEmpty && sticky == true) {
            globalStickyMessageSet.insert(messageJson)
        } else {
            eventSinkSet.forEach { plugin in
                debugPrint("GTLibCoreFlutterPlugin sendMessage - \(messageJson)")
                plugin.eventSink?(messageJson)
            }
        }
    }
    
}
